package com.gframework.biz.datasource.init;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.annotation.Resource;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;

import com.gframework.mybatis.dao.datasource.DynamicDataSourceManager;
import com.zaxxer.hikari.HikariDataSource;

/**
 * 给予数据库T_SYS_DATASOURCE表配置的数据源进行数据源的管理操作.
 * 
 * @since 2.0.0
 * @author Ghwolf
 * 
 */
@ConditionalOnProperty(value = { "gframework.flyway.init-db-data-source",
		"gframework.flyway.init-gframework-basic-table" }, havingValue = "true", matchIfMissing = true)
@ConditionalOnBean(DataSourceAutoConfiguration.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class DataBaseSourceInit implements InitializingBean{
	private static final Logger logger = LoggerFactory.getLogger(DataBaseSourceInit.class);

	/**
	 * 多数据源管理对象
	 */
	@Resource
	private DynamicDataSourceManager dataSourceManager ;
	
	/**
	 * 主数据源
	 */
	@Resource
	private DataSource mainDataSource ;
	
	/**
	 * 查询数据源的sql语句
	 */
	private static final String SEARCH_SQL = "SELECT * FROM T_SYS_DATASOURCE WHERE enabled=1 and deleted=0";
	
	@Override
	public void afterPropertiesSet() throws Exception {
		try (
				Connection conn = this.mainDataSource.getConnection();
				PreparedStatement pstmt = conn.prepareStatement(SEARCH_SQL);
				) {
			pstmt.execute();
			try (ResultSet rs = pstmt.getResultSet();) {
				while (rs.next()) {
					String id = rs.getString("DS_ID");
					String jndi = rs.getString("JNDI");
					String driverClassName = rs.getString("DRIVER_CLASS_NAME");
					String username = rs.getString("USERNAME");
					String password = rs.getString("PASSWORD");
					String url = rs.getString("DB_URL");
					String poolName = rs.getString("POOL_NAME");
					String connectionTestQuery = rs.getString("CONNECTION_TEST_QUERY");
					int maxPoolSize = rs.getInt("MAX_POOL_SIZE");
					int minIdle = rs.getInt("MIN_POOL_SIZE");
					int idleTimeout = rs.getInt("IDLE_TIMEOUT");
					int maxLifetime = rs.getInt("MAX_LIFETIME");
					int loginTimeout = rs.getInt("LOGIN_TIMEOUT");
					int validationTimeoutMs = rs.getInt("VALIDATION_TIMEOUT");
					int connectionTimeoutMs = rs.getInt("CONNECTION_TIMEOUT");

					DataSourceProperties properties = new DataSourceProperties();
					
					properties.setUrl(url);
					properties.setUsername(username);
					properties.setPassword(password);
					if (StringUtils.isNotBlank(driverClassName)) {
						properties.setDriverClassName(driverClassName);
					}
					
					try {
						properties.afterPropertiesSet();
					} catch (Exception e1) {
						logger.error("从数据库添加一个新的数据源出错：id = {}",id,e1);
					}
					HikariDataSource ds = properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
					
					if (StringUtils.isNotBlank(poolName)) {
						ds.setPoolName(poolName);
					}
					if (StringUtils.isNotBlank(connectionTestQuery)) {
						ds.setConnectionTestQuery(connectionTestQuery);
					}
					if (validationTimeoutMs > 0) ds.setValidationTimeout(validationTimeoutMs);
					if (loginTimeout > 0) ds.setLoginTimeout(loginTimeout);
					if (maxPoolSize > 0) ds.setMaximumPoolSize(maxPoolSize);
					if (minIdle > 0) ds.setMinimumIdle(minIdle);
					if (idleTimeout > 0) ds.setIdleTimeout(idleTimeout);
					if (maxLifetime > 0) ds.setMaxLifetime(maxLifetime);
					if (connectionTimeoutMs > 0) ds.setConnectionTimeout(connectionTimeoutMs);
					
					
					this.dataSourceManager.register(id, ds);

					if (jndi != null) {
						try {
							InitialContext context = new InitialContext();
							boolean isInit = System.getProperty(Context.INITIAL_CONTEXT_FACTORY) != null;
							if (isInit) {
								context.bind(jndi,ds);
							}
						} catch (NamingException e) {
							logger.error("绑定数据源到JNDI失败，key={},jndi={}",id,jndi);
						}
					}
					
					if (logger.isInfoEnabled()) {
						logger.info("从数据库添加了一个新的数据源：{}",id);
					}
				}
			}
		} catch (SQLException e) {
			logger.error("从数据库获取数据时发送错误！",e);
		}
	}
}
